package com.dong.es.config;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContextBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.sniff.ElasticsearchNodesSniffer;
import org.elasticsearch.client.sniff.Sniffer;
import org.elasticsearch.client.sniff.SnifferBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.List;

/**
 * EliasticSearch连接池工厂对象
 * @author 00000
 *
 */
public class EsClientPoolFactory implements PooledObjectFactory<EsClient> {

	private HttpHost[] hosts;
	private String username;
	private String password;
	private boolean isSSL;
	private List<String> httpList;

	public EsClientPoolFactory() {
	}

	@PostConstruct
	public void postConstruct() {
		// String http = Global.getConfig("es.hosts");
		hosts = new HttpHost[httpList.size()];
		for (int i = 0; i < hosts.length; i++) {
			String http = httpList.get(i);
			if (isSSL) {
				http = "https://" + http;
			}
			hosts[i] = HttpHost.create(http);
			httpList.set(i, http);
		}
	}

	@Override
	public void activateObject(PooledObject<EsClient> arg0) throws Exception {
//		System.out.println("activateObject");
		
	}
	
	/**
	 * 销毁对象
	 */
	@Override
	public void destroyObject(PooledObject<EsClient> pooledObject) throws Exception {
		EsClient client = pooledObject.getObject();
		client.close();
	}
	
	/**
	 * 生产对象
	 */
//	@SuppressWarnings({ "resource" })
	@Override
	public PooledObject<EsClient> makeObject() throws Exception {
		RestClientBuilder builder = RestClient.builder(hosts);
		CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
		credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
		builder.setHttpClientConfigCallback(
				f -> {
					f.setDefaultCredentialsProvider(credentialsProvider);
					if (isSSL) {
						try {
							return f.setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (e1, e2) -> true).build());
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					return f;
				}
		);
		RestClient restClient = builder.build();
		SnifferBuilder snifferBuilder = Sniffer.builder(restClient);
		if (isSSL) {
			snifferBuilder.setNodesSniffer(new ElasticsearchNodesSniffer(restClient, ElasticsearchNodesSniffer.DEFAULT_SNIFF_REQUEST_TIMEOUT, ElasticsearchNodesSniffer.Scheme.HTTPS));
		}
		Sniffer sniffer = snifferBuilder.build();
		ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());

		ElasticsearchClient elasticsearchClient = new ElasticsearchClient(transport);

		EsClient esClient = new EsClient();

		esClient.setClose(p -> {
			try {
				sniffer.close();
				transport.close();
				restClient.close();
				esClient.setClose(null);
			} catch (IOException e) {
				e.printStackTrace();
			}
			return p;
		});
		esClient.setClient(elasticsearchClient);

		return new DefaultPooledObject<EsClient>(esClient);
	}

	@Override
	public void passivateObject(PooledObject<EsClient> arg0) throws Exception {
//		System.out.println("passivateObject");
	}

	@Override
	public boolean validateObject(PooledObject<EsClient> arg0) {
		return true;
	}

	public HttpHost[] getHosts() {
		return hosts;
	}

	public void setHosts(HttpHost[] hosts) {
		this.hosts = hosts;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public boolean isSSL() {
		return isSSL;
	}

	public void setSSL(boolean SSL) {
		isSSL = SSL;
	}

	public List<String> getHttpList() {
		return httpList;
	}

	public void setHttpList(List<String> httpList) {
		this.httpList = httpList;
	}
}
